
import { Painter, Ring } from '../view/cosmicRing/painter';

function createPendant(context) {
  let t0 = new P(context);
  let pendant = new context.Pendant({
    require : ['three'],
    init : (libs, args) => t0.init(libs, args),
    destroy : () => t0.destroy(),

    // custom function
    collectInfo : () => t0.collectInfo(),
    onMessage : (key, value) => t0.onMessage(key, value),
    registerTimerSupplier : (supplier) => t0.registerTimerSupplier(supplier),
  });
  t0.sendStatus = () => pendant.sendStatus();
  return pendant;
}

/** @type {number[]} */
const offXMap = [];
/** @type {number[]} */
const gamaMap = [];
for (let i = 0; i < 100; i++) {
  let n = 12 * Math.sin(i / 4) / (i + 1) ** 1.5;
  offXMap.push(((n * 100) | 0) / 100);
  n = 1 / 2 ** (i / 20) + 0;
  gamaMap.push(n);
}

/**
 * 初始化参数包括:
 * 
 * dom: 在哪个 div 下建立 canvas
 */
class P {
  constructor(context) {
    global.p = this;
    this.context = context;
    this.tick = this.tick.bind(this);
    /** @type {Ring[]} */
    this.rings = new Array(32).fill().map((_, i) => new Ring(i));

    this.timerSupplier = () => {
      return {
        time: 0, // 秒
        status: 'paused'
      };
    };

    this.lastPulseTime = 0;
    this.allBlack = false;
  }
  
  init(libs, args) {
    this.painter = new Painter({
      three : libs.three,
      dom : args.dom,
      zIndex : -10,
      rings : this.rings,
    });

    requestAnimationFrame(this.tick);
  }

  tick() {
    requestAnimationFrame(this.tick);
    const hasChanged = this.tickRings();
    if (hasChanged) { // 因为除了播放状态, 其它都是黑的, 不需要渲染
      this.painter.render();
    }
  }

  tickRings() {
    const {time, status} = this.timerSupplier();
    const firstPulse = time < 1;
    const now = Date.now();

    if (status == 'playing') {
      this.lastPulseTime = now - (((time * 1000) % 1000) | 0);
    }

    this.rings.forEach((ring, i) => {
      let delta = now - (this.lastPulseTime + i * 10);
      if (delta < 0) {
        if (firstPulse) {
          ring.gama = 0;
          ring.offX = 0;
          return;
        }

        delta += 1000;
      }
      let index = (delta / 10) | 0;
      ring.gama = index <= 100 ? gamaMap[index] : 0;
      ring.offX = index <= 100 ? offXMap[index] : 0;
    });

    const lastBlack = this.allBlack;
    this.allBlack = this.rings.some(r => r.gama == 0);
    return !(lastBlack && this.allBlack);
  }

  destroy() {}

  collectInfo() {
    return {};
  }

  onMessage(key, value) {
    console.log('cosmicRing 收到信息', key, value);
  }

  sendStatus = () => {};

  /**
   * @param {()=>{time:number,status:string}} supplier 
   */
  registerTimerSupplier(supplier) {
    this.timerSupplier = supplier;
  }
}

export default createPendant;
